/*
 *  tropeTreeNode.cpp
 *  tropeProject
 *
 *  Created by Jared Schiffman on 12/5/10.
 *  Copyright 2010 Potion. All rights reserved.
 *
 */

#include "tropeTreeNode.h"


// ============================================================= //
// ======================= tropeTreeNode ======================= //


tropeTreeNode::tropeTreeNode()
{
	int numSlots = getNumSlots();
	if ( numSlots > 0 )
	{
		children.reserve( numSlots );
		for( int i=0; i<children.size(); i++ )
			children[i] = nullNode();
	}
}

tropeTreeNode::~tropeTreeNode()
{
}


tropeTreeNode*					tropeTreeNode::getChild( int i )
{
	if ( i<0 || i>=children.size() )
		return NULL;
	return children[i];
}

tropeTreeNode*					tropeTreeNode::getChildByName( std::string _name )
{
	for( int i=0; i<children.size(); i++ )
		if ( children[i]->name == _name )
			return children[i];
	return NULL;
}



bool					tropeTreeNode::addChild( tropeTreeNode* T )
{
	if ( allowChildAddition(T) )
	{
		children.push_back(T);
		return true;
	}
	return false;
}


bool					tropeTreeNode::insertChildAt( int index, tropeTreeNode* T )
{
	if ( index<0 || index>=children.size() )
		return false;
	
	if ( allowChildInsertion( index,T ) )
	{
		return true;
		children.insert( children.begin()+index, T );
	}
	return false;
}


bool					tropeTreeNode::setChildAt( int index, tropeTreeNode* T )
{
	if ( index<0 || index>=children.size() )
		return false;
	
	if ( allowChildSetting( index,T ) )
	{
		return true;
		children[index] = T;
	}
	return false;
}

tropeTreeNode *tropeTreeNode::TROPE_NULL_NODE = NULL;

tropeTreeNode* tropeTreeNode::nullNode() {
	if(!TROPE_NULL_NODE) {
		TROPE_NULL_NODE = new tropeTreeNode();
		TROPE_NULL_NODE->setName("NULL NODE");
	}
	return TROPE_NULL_NODE;
}

void					tropeTreeNode::changeNotification( tropeTreeNode *node, tropeChangeType change )
{
	for( int i=0; i<children.size(); i++ )
		children[i]->changeNotification( node, change );
}


// ============================================================= //
// ============ tropeVariableInstantiationNode ================= //

bool	tropeVariableInstantiationNode::allowChildAddition( tropeTreeNode* T )
{
	if ( numChildren() > 0 )
		return false;
	
	// confirm type is user type (not built-in type)
	tropeTypeID variableType = variableDeclaration->variableType;
	tropeType* theType = tropeType::getType( variableType );
	if ( theType->metaType != TROPE_USER_TYPE )
		return false;
	
	tropeSyntaxType syntaxType = T->getSyntaxType();
	if ( syntaxType == TROPE_VARIABLE_INSTANTIATION || syntaxType == TROPE_METHOD_INSTANTIATION  )
		return true;
	return false;	
}

bool	tropeVariableInstantiationNode::checkSyntax()
{
	if ( numChildren()==0 )
		return true;
	
	tropeTreeNode* child = getChild(0);
	
	if ( child->getSyntaxType() == TROPE_VARIABLE_INSTANTIATION )
	{
		tropeVariableDeclarationNode* member = (tropeVariableDeclarationNode*) child;
		tropeTypeID variableType = member->variableType;
		tropeType* theType = tropeType::getType( variableType );
		
		bool foundIt = false;
		for( int i=0; i<theType->variableList.size(); i++ )
		{
			tropeVariableDeclarationNode* typeMember = theType->variableList[i];
			tropeTypeID variableType = typeMember->variableType;
			tropeType* typeMemberType = tropeType::getType( variableType );
			if ( typeMemberType == theType )
				foundIt = true;
		}
		return foundIt;
	}
	
	/*if ( T->getSyntaxType() == TROPE_METHOD_INSTANTIATION )
	{
		
	}*/
	return false;
}


// ============================================================= //
// =================== tropeExpressionNode ===================== //

tropeExpressionNode::tropeExpressionNode( tropeTypeID _restrictionType )
{
	restrictionType = _restrictionType;
}


bool	tropeExpressionNode::allowChildAddition( tropeTreeNode* T )
{
	tropeSyntaxType syntaxType = T->getSyntaxType();
	
	if ( syntaxType == TROPE_CONSTANT || syntaxType == TROPE_VARIABLE_INSTANTIATION || 
		syntaxType == TROPE_METHOD_INSTANTIATION || syntaxType == TROPE_OPERATOR )
		return true;
	return false;
}


tropeTypeID		tropeExpressionNode::getReturnType()
{
	if ( restrictionType == TROPE_NULL_TYPE )
	{
		// do evaluation of children and return resulting type
		return TROPE_NULL_TYPE;		// temporary
	}
	else
	{
		return restrictionType;
	}
}

bool		tropeExpressionNode::checkSyntax()
{
	if ( restrictionType == TROPE_NULL_TYPE )
		return true;
	else
	{
		// parse expression, build internal operator tree, determine return type
		tropeTypeID parsedType; // call parsing function
		if ( parsedType == restrictionType )
			return true;
		else
			return false;
	}
}


// ============================================================= //
// ================== tropeCodeBlockNode ======================= //

bool	tropeCodeBlockNode::allowChildAddition( tropeTreeNode* T )
{
	tropeSyntaxType syntaxType = T->getSyntaxType();
	
	if ( syntaxType == TROPE_EXPRESSION || syntaxType == TROPE_IF_STATEMENT || 
		syntaxType == TROPE_WHILE_STATEMENT || syntaxType == TROPE_FOR_STATEMENT ||
		syntaxType == TROPE_RETURN_STATEMENT)
		return true;
	return false;
}


// ============================================================= //
// ================ tropeLoopCodeBlockNode ===================== //

bool	tropeLoopCodeBlockNode::allowChildAddition( tropeTreeNode* T )
{
	tropeSyntaxType syntaxType = T->getSyntaxType();
	
	if ( syntaxType == TROPE_EXPRESSION || syntaxType == TROPE_IF_STATEMENT || 
		syntaxType == TROPE_WHILE_STATEMENT || syntaxType == TROPE_FOR_STATEMENT ||
		syntaxType == TROPE_RETURN_STATEMENT || 
		syntaxType == TROPE_BREAK_STATEMENT || syntaxType == TROPE_CONTINUE_STATEMENT )
		return true;
	return false;
}



// ============================================================= //
// ================== tropeIfStatementNode ===================== //

tropeIfStatementNode::tropeIfStatementNode()
{
	setChildAt( SLOT_CONDITION, new tropeExpressionNode( TROPE_BOOLEAN_TYPE ) );
	setChildAt( SLOT_CODE_BLOCK, new tropeCodeBlockNode() );
}


// ============================================================= //
// =============== tropeWhileStatementNode ===================== //

tropeWhileStatementNode::tropeWhileStatementNode()
{
	setChildAt( SLOT_CONDITION, new tropeExpressionNode( TROPE_BOOLEAN_TYPE ) );
	setChildAt( SLOT_CODE_BLOCK, new tropeLoopCodeBlockNode() );
}


// ============================================================= //
// =================== tropeForStatementNode =================== //

tropeForStatementNode::tropeForStatementNode()
{
	setChildAt( SLOT_FOR_FIRST, new tropeExpressionNode() );
	setChildAt( SLOT_FOR_SECOND, new tropeExpressionNode( TROPE_BOOLEAN_TYPE ) );
	setChildAt( SLOT_FOR_THIRD, new tropeExpressionNode() );
	setChildAt( SLOT_FOR_CODE_BLOCK, new tropeLoopCodeBlockNode() );
}



// ============================================================= //
// ================ tropeVariableDeclarationListNode =========== //

bool	tropeVariableDeclarationListNode::allowChildAddition( tropeTreeNode* T )
{
	tropeSyntaxType syntaxType = T->getSyntaxType();
	
	if ( syntaxType == TROPE_VARIABLE_DECLARATION )
		return true;
	return false;
}


// ============================================================= //
// ================ tropeMethodDeclarationNode ================= //

tropeMethodDeclarationNode::tropeMethodDeclarationNode()
{	
	setChildAt( SLOT_INPUT_VARIABLES, new tropeVariableDeclarationListNode() );
	setChildAt( SLOT_LOCAL_VARIABLES, new tropeVariableDeclarationListNode() );
	setChildAt( SLOT_RETURN_VARIABLES, new tropeVariableDeclarationListNode() );
	setChildAt( SLOT_CODE_BLOCK, new tropeCodeBlockNode() );
}



